#!/bin/sh
# Bind Intel igb interrupt threads to different cores
# Adapted from same chelsio RC script by farrokhi@FreeBSD.org

# PROVIDE:	igb_affinity
# REQUIRE:	FILESYSTEMS netif
# KEYWORD:	nojail

#
# Add the following lines to /etc/rc.conf.local or /etc/rc.conf
# to enable this service:
#
# igb_affinity_enable (bool):   Set to NO by default.
#               Set it to YES to bind interrupt threads to different cores
# igb_affinity_avoidncpu (int):  0 by default.
#		Set to number of CPU to exclude from binding

. /etc/rc.subr

name="igb_affinity"
rcvar=${name}_enable

start_cmd="igb_affinity_start"

igb_affinity_start()
{
	# Need an Intel igb NIC
	NQ=$(/sbin/sysctl -ni dev.igb.0.link_irq)
	if [ -z "${NQ}" ]; then
		echo "No Intel igb port detected"
		exit 0;
	fi

	# Work with 2 CPU minimum
	NCPU=$(/sbin/sysctl -n hw.ncpu)
	if [ ${NCPU} -le 2 ]; then
		echo "Not enought CPU detected"
		exit 0
	fi

	# Exclude some CPU from binding
	NCPU=$((NCPU - ${igb_affinity_avoidncpu}))
	CPU=0
	igb=$(/sbin/sysctl dev.igb. | grep -c disable_msix)
	for i in $(seq 0 $((igb - 1))); do
		for IRQ in `/usr/bin/vmstat -ai |\
	    	/usr/bin/sed -nE "/igb${i}:rxq./ s/irq([[:digit:]]+):.*/\1/p"`; do
			echo "Bind igb${i} IRQ ${IRQ} to CPU ${CPU}"
			/usr/bin/cpuset -l ${CPU} -x ${IRQ}
			CPU=$(((CPU + 1) % NCPU))
		done
		CPU=0
	done
}

load_rc_config $name

: ${igb_affinity_enable="NO"}
: ${igb_affinity_avoidncpu=0}

run_rc_command "$1"
